<?php
/**
 * | 节程 [ 节程赋能开发者，助力企业发展 ]
 * +----------------------------------------------------------------------
 *  | Copyright (c) 2020~2029 温州惊蛰网络科技有限公司 All rights reserved.
 * +----------------------------------------------------------------------
 *  | Licensed 节程并不是自由软件，未经许可不能去掉节程相关版权
 * +----------------------------------------------------------------------
 */
declare (strict_types=1);

namespace app\utils;

use app\index\model\AliSmsTemplate;
use app\index\model\MsgTemplate;
use app\index\model\WechatTemplate;
use app\index\model\WxaMessage;
use app\index\model\Configuration;
use think\Exception;
use think\facade\Config;
use think\facade\Db;
use think\Model;
use WeChat\Template as WxTemplate;
use WeMini\Newtmpl;
use app\madmin\model\MallLog;

/**
 * 消息发送工具类
 * @package app\utils
 */
class SendMsg
{

    private $scene;
    private $scenarized;
    private $type;
    private $baseTemplateId;
    private $user;
    private $indexUser;

    /**
     * SendMsgService constructor.
     * @param $type string 场景值
     */
    public function __construct($type)
    {
        //获取场景商城变量
        $load = Config::load('extension/scene', 'scene');
        $this->scenarized = isset(Config::load('extension/scenarized', 'scenarized')[$type]) ? Config::load('extension/scenarized', 'scenarized')[$type] : null;
        $this->scene = $load[$type];
        $this->type = $type;
        $this->baseTemplateId = Config::load('extension/baseTemplateId', 'baseTemplateId');
        global $user;
        $this->user = $user;
    }

    /**
     * 发送消息
     * @param $user Model 用户
     * @param $data array 数据
     * @param $url null|string 回调地址
     * @return bool
     * @throws Exception
     * @throws \WeChat\Exceptions\InvalidResponseException
     * @throws \WeChat\Exceptions\LocalCacheException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function send($user, $data, $url = null)
    {
        $this->indexUser = $user;
        if (!empty($user->userWx)) {
            switch ($user->userWx->type) {
                case 1:
                    $channel = "2,3"; // 小程序
                    break;
                case 2:
                    $channel = "1,3"; // 微信公众号
                    break;
                case 3:
                    $channel = "3";
            }
        } else {
            $channel = "3"; // 短信
        }
        global $mid;
        $mid = empty($user->mall_id) ? $mid : $user->mall_id;
        $mj = ["订单付款通知", "订单收货通知", "订单售后通知"];
        if (in_array($this->type, $mj)) {
            $channel = "1,2,3";
        }
        $msgTemplateList = Db::name('msg_template')
            ->where('mall_id', $mid)
            ->where(['type' => $this->type])
            ->where('channel', 'in', $channel)
            ->where('status', 1)
            ->select();
        foreach ($msgTemplateList as $k => $v) {
            $openid = isset($user->userWx->openid) ? $user->userWx->openid : "";
            $mobile = $data['buyer_mobile'] ?? $user->mobile;
            $mj = ["订单付款通知", "订单收货通知", "订单售后通知"];
            if (in_array($v['type'], $mj)) {
                $openid = "";
            }
            if ($v['user_id'] > 0) {
                $openid = Db::name("user_wx")->field("openid")->where('user_id', $v['user_id'])->find()['openid'];
                $mobile = Db::name('user')->field("mobile")->find($v['user_id'])['mobile'];
            }
            switch ($v['channel']) {
                case 1:
                    $this->sendWxMsg($v, $openid, $data, $url);
                    break;
                case 2:
                    $this->sendWxaMsg($openid, $data, $url);
                    break;
                case 3:
                    $this->sendAliMsg($v, $mobile, $data, $mid);
                    break;
            }
        }
        return true;

    }

    /**
     * 发送ali短信消息
     * @param $msgTemplate Model 场景
     * @param $mobile string 用户手机
     * @param $data array 数据
     * @return array|bool
     * @throws Exception
     * @throws \WeChat\Exceptions\InvalidResponseException
     * @throws \WeChat\Exceptions\LocalCacheException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function sendAliMsg($msgTemplate, $mobile, $data, $mid = 0)
    {
        if (empty($msgTemplate['template_id'])) {
            throw new Exception("短信模版未配置／配置错误！", HTTP_NOTACCEPT);
        }
        $aliSmsTemplate = Db::name('ali_sms_template')
            ->where('mall_id', $mid)
            ->where('status', 1)
            ->find($msgTemplate['template_id']);
        $templates = json_decode($aliSmsTemplate['attr']);
        $attr = [];
        foreach ($templates as $k => $v) {
            $attr[$k] = $data[$this->scene[$v]];
        }
        $data = array_merge(
            [
                'RegionId' => "cn-hangzhou",
                'PhoneNumbers' => $mobile,
                'SignName' => $aliSmsTemplate['sign_name'],
                'TemplateCode' => $aliSmsTemplate['template_code'],
            ], ["TemplateParam" => json_encode($attr)]);
        try {
            if(empty($mid)){
                $aliSms = new AliSms();
            } else {
                $aliSms = new AliSms((int)$mid);
            }
        } catch (\Exception $e) {
            return false;
        }
        try {
            $res = $aliSms->SendSms($data);
            if (isset($res[1]) && $res[1]['Message'] != "OK") {
                Db::name("mall_log")->save([
                    'mall_id' => $mid ?? 0,
                    'action' => 'app/utils/SendMsg/:sendAliMsg',
                    'message' => $res[1]['Message'],
                    'data' => serialize($res),
                    'time' => date("Y-m-d H:i:s", time()),
                ]);
            }
        } catch (Exception $e) {
            Db::name("mall_log")->save([
                'mall_id' => $mid ?? 0,
                'action' => 'app/utils/SendMsg/:sendAliMsg',
                'message' => $e->getMessage(),
                'data' => serialize($res),
                'time' => date("Y-m-d H:i:s", time()),
            ]);
        }
        return $res;
    }

    /**
     * 发送微信消息
     * @param $openid string 用户openid
     * @param $url string 点击回调地址
     * @param $data array 数据
     * @return array|bool
     * @throws Exception
     * @throws \WeChat\Exceptions\InvalidResponseException
     * @throws \WeChat\Exceptions\LocalCacheException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function sendWxaMsg($openid, $data, $url)
    {
        global $mid;
        $mid = empty($this->user->mall_id) ? $mid : $this->user->mall_id;
        //获取微信配置
        $configuration = Configuration::where(['type' => 'wxa', 'status' => 1])->value("configuration");
        if (empty($configuration))
            return false;
        $configuration = json_decode($configuration, true);
        //获取模板配置
        $templateData = self::getBaseWxaTemplate(2, $openid, $data, $url);
        if (!$templateData)
            return false;
        //获取模板实例
        $template = new Newtmpl($configuration);
        try {
            $res = $template->send($templateData);
        } catch (\Exception $exception) {
            MallLog::create([
                'action' => 'app/utils/SendMsg/:sendWxaMsg',
                'message' => $exception->getMessage(),
                'data' => serialize($templateData),
                'time' => date("Y-m-d H:i:s", time()),
            ]);
            $res = "模版消息发送失败";
        }
        return $res;
    }


    /**
     * 发送微信消息
     * @param $msgTemplate Model 场景
     * @param $openid string 用户openid
     * @param $url string|null 点击回调地址
     * @param $data array 数据
     * @return array|bool
     * @throws Exception
     * @throws \WeChat\Exceptions\InvalidResponseException
     * @throws \WeChat\Exceptions\LocalCacheException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function sendWxMsg($msgTemplate, string $openid, array $data, ?string $url)
    {
        new Configuration(['mall_id' => $msgTemplate['mall_id']]);
        //获取微信配置
        $configuration = Configuration::where(['type' => 'wx'])->value('configuration');
        if (empty($configuration))
            return false;

        $configuration = json_decode($configuration, true);

        //获取模板配置
        if (empty($msgTemplate->is_base)) { //默认模板
            $wechatTemplate = WechatTemplate::find($msgTemplate['template_id']);
            if (empty($wechatTemplate))
                return false;
            $templateData = $this->getTemplate($wechatTemplate, $openid, $data, $url);
        } else { //非默认模板
            $templateData = self::getBaseWxTemplate(1, $openid, $data, $url);
        }
        //获取模板实例
        $template = new WxTemplate($configuration);
        try {
            $res = $template->send($templateData);
        } catch (\Exception $exception) {
            MallLog::create([
                'action' => 'app/utils/SendMsg/:sendWxMsg',
                'message' => $exception->getMessage(),
                'data' => serialize($templateData),
                'time' => date("Y-m-d H:i:s", time()),
            ]);
            $res = "模版消息发送失败";
        }
        return $res;
    }

    /**
     * 整理默认微信公众号模板数据
     * @param $type string 场景
     * @param $channel int 渠道
     * @param $openid string 用户openid
     * @param $url string|null 点击回调地址
     * @param $data array 数据
     * @return mixed
     */
    private function getBaseWxTemplate(int $channel, string $openid, array $data, ?string $url)
    {
        //获取基础模板列表
        $this->scenarized = Config::load('extension/scenarized', 'scenarized');

        //整理模板数据
        $template = $this->scenarized[$this->type][$channel]['template'];
        $template['template_id'] = $this->baseTemplateId[$this->type][$channel];
        $template['touser'] = $openid;
        $template['url'] = $url;
        foreach ($template['data'] as $k => $v) {
            if ($k == "first" || $k == "remark")
                continue;
            $template['data'][$k]['value'] = $data[$v['value']];
        }
        return $template;
    }

    /**
     * 整理默认微信小程序模板数据
     * @param $type string 场景
     * @param $channel int 渠道
     * @param $openid string 用户openid
     * @param $url string|null 点击回调地址
     * @param $data array 数据
     * @return mixed
     */
    private function getBaseWxaTemplate(int $channel, string $openid, array $data, ?string $url)
    {
        //获取基础模板列表
        $msg = MsgTemplate::where(['channel' => $channel, 'type' => $this->type])->find();
        //整理模板数据
        $template = WechatTemplate::find($msg['template_id']);
//        $wxaMessage = WxaMessage::where(['user_id' => $this->indexUser->id, 'template_id' => $template['$template_id']])
//            ->lock(true)->find();
//        if (!$wxaMessage) {
//            return false;
//        } else {
//            $wxaMessage->count == 1 ?
//                $wxaMessage->delete() :
//                $wxaMessage->dec("count", 1)->update();
//        }
        $send['template_id'] = $template['template_id'];
        $send['touser'] = $openid;
        if (!empty($url)) {
            $send['page'] = $url;
        } else {
            $send['page'] = "index";
        }
        foreach ($template['attr'] as $k => $v) {
            $send['data'][$v] = ["value" => $data[$v]];
        }
        return $send;
    }

    /**
     * 整理微信模板消息
     * @param $openid string 用户openid
     * @param $url string|null 点击回调地址
     * @param $wechatTemplate Model 模板配置对象
     * @param $data array 数据
     * @return array
     */
    private function getTemplate(Model $wechatTemplate, string $openid, array $data, ?string $url)
    {
        //设置模板数据
        $template = [
            "touser" => $openid,
            "template_id" => $wechatTemplate->template_id,
            "url" => $url,
        ];
        //设置模板内的data内的first数据
        $wxTemplateData = [
            "first" => [
//                "value" => $data[$this->scene[$wechatTemplate->first->value]],
                "value" => $wechatTemplate->first->value,
                'color' => $wechatTemplate->first->color
            ]
        ];
        //整合data内attr数据
        if (!empty($wechatTemplate->attr)) {
            $attr = [];
            $other = ['first', 'remark'];
            foreach ($this->scenarized[1]['template']['data'] as $k => $v) {
                if (!in_array($k, $other)) {
                    $attr[$k] = [
                        "value" => $data[$v['value']],
                        'color' => $v['color']
                    ];
                }
            }
            $wxTemplateData = array_merge($wxTemplateData, $attr);
        }

        //整合data内remark数据
        if (!empty($wechatTemplate->remark)) {
            $remark['remark'] = [
//                "value" => $data[$this->scene[$wechatTemplate->remark->value]],
                "value" => $wechatTemplate->remark->value,
                'color' => $wechatTemplate->remark->color
            ];
            $wxTemplateData = array_merge($wxTemplateData, $remark);
        }
        $template['data'] = $wxTemplateData;
        return $template;
    }


}